home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / demo / igps_102.zip / PHONEVW.CPP < prev    next >
C/C++ Source or Header  |  1994-12-01  |  40KB  |  1,195 lines

  1. ///////////////////////////////////////////////////////////////////////////////////
  2. // Internet Global Phone Project
  3. // CPhoneView  phonevw.cpp : implementation of the CPhoneView class
  4. //
  5. // The Phoneview class is responsible for user interface handling and low level 
  6. // audio handling (including compression/decompression via GSM).
  7. //
  8. ////////////////////////////////////////////////////////////////////////////////////
  9. // Copyright (c) 1993-1994    microWonders Inc.  All rights reserved.
  10. //                                                                         
  11. // AN OPEN INVITION TO BUILD UPON AND CONTRIBUTE TO THE PUBLIC TECHNOLOGY POOL:
  12. // You are encouraged to redistribute, and build upon the technologies presented 
  13. // in this source module and the accompanying article in Dr. Dobb's Journal provided 
  14. // all the conditions listed in the MUSTREAD.TXT file, included with this 
  15. // distribution, are met.
  16. ////////////////////////////////////////////////////////////////////////////////////
  17. // Full DUPLEX is not possible currently due to drivers restriction, either sound 
  18. // rec or play only
  19. //
  20. // June 11,1994  Eliminate lock-step transmit-receive requirement
  21. // June 10,1994     Added fool-proof checks on button states to avoid
  22. //                 crashes due to multiple button presses (SL)
  23. // June 5, 1994  fixed occasional buffer drop out due to OnRecordDone resetting
  24. //               some variables incorrectly (SL)  
  25. // June 2, 1994  fixed playback always at length - sizeof(GSM_FRAME) problem (SL)
  26. // May 20, 1994  separated OLE2 dependencies, no longer needs OLE DLLs (SL)
  27. // May 10, 1994  added 16 bit sound support via #define HI_FIDELITY switch(SL)
  28. // 
  29. //===================================================================================
  30. //
  31. //    UMIST distribution Revisions
  32. //
  33. // Nov 30, 1994        changed sampling frequency to 11025hz (PA)
  34. //                    fixed bug that crashed program if it finished compressing
  35. //                    first block while second was still recording. (PA)
  36.  
  37.  
  38.  
  39. #include "stdafx.h" 
  40. #include "mmsystem.h"
  41. #include "mphone.h"
  42.  
  43. #include "phonedoc.h"  
  44. #include "wsmin.h" 
  45. #include "socket.h"
  46. #include "talksock.h"
  47. #include "phonevw.h"
  48. #include "gsm.h" 
  49.  
  50. #include "dlg_host.h"
  51. #ifdef _DEBUG
  52. #undef THIS_FILE
  53. static char BASED_CODE THIS_FILE[] = __FILE__;
  54. #endif
  55.  
  56. IMPLEMENT_DYNCREATE(CPhoneView, CEditView)
  57.  
  58. BEGIN_MESSAGE_MAP(CPhoneView, CEditView)
  59.     //{{AFX_MSG_MAP(CPhoneView)   
  60.       ON_MESSAGE(MM_WIM_CLOSE, OnWaveInClose)
  61.         ON_MESSAGE(MM_WIM_OPEN, OnWaveInOpen)      
  62.         ON_MESSAGE(MM_WIM_DATA, OnWaveInData)
  63.         ON_MESSAGE(MM_WOM_DONE, OnWaveOutDone) 
  64.       ON_MESSAGE(PHONEMSG_RECORD_DONE, OnRecordDone)
  65.       ON_MESSAGE(PHONEMSG_COMPRESS_DONE, OnCompressDone)
  66.       ON_MESSAGE(WM_WSANOTIFY, OnClientNotify)
  67.       ON_UPDATE_COMMAND_UI(ID_PHONE_RECORD, OnUpdatePhRecord)
  68.       ON_UPDATE_COMMAND_UI(ID_PHONE_SEND, OnUpdatePhSend)
  69.       ON_COMMAND(ID_PHONE_RECORD, OnPhRecord)
  70.       ON_COMMAND(ID_PHONE_SEND, OnPhSend)
  71.       ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
  72.     //}}AFX_MSG_MAP
  73. END_MESSAGE_MAP()
  74.  
  75. /////////////////////////////////////////////////////////////////////////////
  76. // CPhoneView construction/destruction
  77.  
  78. CPhoneView::CPhoneView()
  79. {
  80.     // TODO: add construction code here   
  81.     m_recording = FALSE;
  82.     m_transmitting = FALSE;
  83.     m_hWaveIn = 0;           
  84.     m_hWaveOut = 0;
  85.     if (!(m_hGsm = gsm_create()))
  86.     {       
  87.      AfxGetMainWnd()->MessageBox("Cannot initialize gsm?");
  88.      return;
  89.     }              
  90.     // set up compression buffer
  91.     m_CompBufSize = 0L;
  92.     m_hCompress = GlobalAlloc(GHND , (DWORD) COMPRESSED_BUFSIZE);
  93.     if (!m_hCompress)
  94.     {
  95.       AfxGetMainWnd()->MessageBox("cannot allocate compress buffer!");
  96.       return;
  97.     }             
  98.     m_CompressedBuf = (HPSTR) GlobalLock(m_hCompress);
  99.     if (!m_CompressedBuf)
  100.     {
  101.       GlobalUnlock(m_hCompress);
  102.       GlobalFree(m_hCompress);
  103.       AfxGetMainWnd()->MessageBox("cannot lock compress buffer!");
  104.       return;
  105.     }               
  106.     
  107.     ((CPhoneApp *) AfxGetApp())->m_OnlyView =  this;  // hook idle thread 
  108.     m_compressWork = FALSE; // no work for background threads 
  109.     m_decompressWork = FALSE;   
  110.     
  111.     m_state.doneBuffer = FALSE;  // nothing to do initially 
  112.     m_state.maxIter = 0L;
  113.     m_state.linearCount = 0; 
  114.     m_state.i = 0L; 
  115.     m_state.lpWaveHdr = (LPWAVEHDR) 0;
  116.     m_state.lpData = (HPSTR) 0;         
  117.     
  118.    m_ListenerStarted = FALSE;
  119. }
  120.  
  121. CPhoneView::~CPhoneView()
  122. {  
  123.       GlobalUnlock(m_hCompress);
  124.       GlobalFree(m_hCompress);
  125.       gsm_destroy(m_hGsm);
  126. }
  127.  
  128. /////////////////////////////////////////////////////////////////////////////
  129. // CPhoneView drawing
  130.  
  131. void CPhoneView::OnDraw(CDC* pDC)
  132. {
  133.     CPhoneDoc* pDoc = GetDocument();
  134.     ASSERT_VALID(pDoc);
  135.  
  136. }
  137.  
  138. /////////////////////////////////////////////////////////////////////////////
  139. // CPhoneView diagnostics
  140.  
  141. #ifdef _DEBUG
  142. void CPhoneView::AssertValid() const
  143. {
  144.     CEditView::AssertValid();
  145. }
  146.  
  147. void CPhoneView::Dump(CDumpContext& dc) const
  148. {
  149.     CEditView::Dump(dc);
  150. }
  151.  
  152. CPhoneDoc* CPhoneView::GetDocument() // non-debug version is inline
  153. {
  154.     ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPhoneDoc)));
  155.     return (CPhoneDoc*)m_pDocument;
  156. }
  157. #endif //_DEBUG
  158.  
  159. /////////////////////////////////////////////////////////////////////////////
  160. // CPhoneView message handlers
  161.  
  162. void CPhoneView::OnUpdatePhRecord(CCmdUI* pCmdUI)
  163. {                                       
  164.      //
  165.     // Set appropriate states of the UI buttons
  166.     // after the recording button is pressed
  167.        if (!m_recording)
  168.       {
  169.         if(!m_transmitting)
  170.             {
  171.             pCmdUI->Enable(TRUE);
  172.             pCmdUI->SetCheck(FALSE);
  173.             }
  174.         else 
  175.           pCmdUI->Enable(FALSE); 
  176.       }
  177.       else // recording
  178.       {      
  179.         pCmdUI->Enable(TRUE);
  180.         pCmdUI->SetCheck(TRUE);
  181.       }
  182.  
  183. }
  184.  
  185. void CPhoneView::OnUpdatePhSend(CCmdUI* pCmdUI)
  186. {
  187.    // update user interface after the send button
  188.    // is pressed
  189.     if (m_transmitting)      
  190.      {
  191.       pCmdUI->Enable(TRUE);
  192.       pCmdUI->SetCheck(TRUE);
  193.      }
  194.     else // not transmitting
  195.      {
  196.       if (m_recording)     
  197.         {
  198.         pCmdUI->Enable(TRUE);
  199.         pCmdUI->SetCheck(FALSE);
  200.         }
  201.       else
  202.         {
  203.          pCmdUI->Enable(FALSE);
  204.        } 
  205.     }   
  206.  
  207.     
  208. }
  209.  
  210. void CPhoneView::OnPhRecord()
  211. {   
  212.      UINT retval;
  213.     
  214.     // Start the recording process by seizing the WaveIn Device
  215.     // and start sending two priming audio buffer to it
  216.  
  217.     if ((!m_transmitting) && (!m_recording))  // prevent users from repeat presses!
  218.     {
  219.     m_recording = TRUE;   
  220.     m_transmitting = FALSE;
  221.       
  222.    
  223.     PCMWAVEFORMAT format;
  224.     LPWAVEHDR lpWaveHdr;
  225. #ifdef HIGH_FIDELITY       
  226.     format.wf.wFormatTag =  WAVE_FORMAT_PCM;
  227.     format.wf.nChannels = 1;
  228.     format.wf.nSamplesPerSec = 11025;
  229.     format.wf.nAvgBytesPerSec = 22050;
  230.     format.wf.nBlockAlign = 2;
  231.     format.wBitsPerSample = 16; 
  232. #else
  233.     format.wf.wFormatTag =  WAVE_FORMAT_PCM;
  234.     format.wf.nChannels = 1;
  235.     format.wf.nSamplesPerSec = 11025;
  236.     format.wf.nAvgBytesPerSec = 11025;
  237.     format.wf.nBlockAlign = 1;
  238.     format.wBitsPerSample = 8; 
  239. #endif    
  240.     
  241.     // open the device, have message come back to frame window   
  242.     if(::waveInOpen( (LPHWAVEIN) &m_hWaveIn, 0, (LPWAVEFORMAT) &format,  (UINT) m_hWnd,(DWORD) 0,(DWORD) CALLBACK_WINDOW))
  243.     { 
  244.     AfxGetMainWnd()->MessageBox("Cannot open audio input device!");     
  245.     m_recording = FALSE;
  246.     return;
  247.     }
  248.     if(MakeWaveInBuffer(m_hWaveIn, lpWaveHdr, PHONE_WAVEIN_BUFSIZE)== FALSE)
  249.     {                   
  250.     // will announce message internally
  251.     m_recording = FALSE;
  252.     return;               
  253.     }
  254.     if (retval = waveInAddBuffer(m_hWaveIn, lpWaveHdr,  sizeof(WAVEHDR)))
  255.     {
  256.     AfxGetMainWnd()->MessageBox("Cannot add buffer to driver pool!");
  257.     DestroyWaveInBuffer(m_hWaveIn, lpWaveHdr);
  258.     m_recording = FALSE;
  259.     return;
  260.     }       
  261.     // allocate 2nd buffer
  262.     if(MakeWaveInBuffer(m_hWaveIn, lpWaveHdr, PHONE_WAVEIN_BUFSIZE)== FALSE)
  263.     {                   
  264.     // will announce message internally
  265.     m_recording = FALSE;               
  266.     return;
  267.     }
  268.     if (retval = waveInAddBuffer(m_hWaveIn, lpWaveHdr, sizeof(WAVEHDR)))
  269.     {
  270.     AfxGetMainWnd()->MessageBox("Cannot add buffer2 to driver pool!");
  271.     DestroyWaveInBuffer(m_hWaveIn, lpWaveHdr);
  272.     m_recording = FALSE;
  273.     return;                                        
  274.     }
  275.     TRACE("Just sent the first 2 buffers to record!\n");
  276.     if (waveInStart(m_hWaveIn))
  277.     {
  278.     AfxGetMainWnd()->MessageBox("Cannot start recording!");
  279.     m_recording = FALSE;
  280.     return;
  281.     }
  282.     } // of not transmitting
  283. }
  284.  
  285. void CPhoneView::OnPhSend()
  286. {
  287.     // User pressed the Send button.  It is time now to stop the recording
  288.     // thread and start the transmission thread;  BUT remember that the compression
  289.     // thread maynot be finished yet!  We synchronize without
  290.     // locking up by stopping the WaveIn (recording) device, and putting a
  291.     // 'completed' message into the message queue.   
  292.          
  293.     if (m_recording)
  294.     {
  295.     m_transmitting = TRUE;
  296.     m_recording = FALSE;
  297.     // stop recording  
  298.       if( waveInStop(m_hWaveIn))
  299.       {   
  300.        AfxGetMainWnd()->MessageBox("Something funny, cannot stop recording.");
  301.        m_transmitting = FALSE;
  302.        return;
  303.        }
  304.       if( waveInReset(m_hWaveIn))
  305.       {
  306.        AfxGetMainWnd()->MessageBox("Something funny, cannot reset.");
  307.        m_transmitting = FALSE;
  308.        return;
  309.       }   
  310.       // can't process right the way, got to give the MM process
  311.       // some slack
  312.       PostMessage(PHONEMSG_RECORD_DONE);  
  313.       
  314.     }           
  315. }
  316.  
  317. LRESULT CPhoneView::OnCompressDone(WPARAM wParam, LPARAM lParam)
  318. {
  319.  
  320.    //  Start the transmission process now that the background compression
  321.    //  thread has completed.
  322.    
  323.    m_TalkClient.Connect(TCPSOCK, m_ClientAddress,  IGP_PORT, 
  324.      30000, m_hWnd, NULL, 10, m_CompressedBuf, 
  325.        m_CompBufSize  );  // 30000 ms before timer ticks, timer currently not used
  326.    m_transmitting = TRUE; 
  327.    m_CompBufSize = 0; // reset buffer size for next recording! 
  328.    return 0L;
  329. }  
  330.     
  331. /////////////////////////////////////////////////
  332. //
  333. // Multimedia Message Handling
  334. //
  335. // Handle the low level audio 
  336. //
  337.  
  338. LRESULT CPhoneView::OnWaveInClose(WPARAM wParam, LPARAM lParam)
  339. {       
  340. // Not used currently  
  341. //MessageBox("Hi, I'm Here!");
  342. return 0L;
  343. }  
  344.  
  345. LRESULT CPhoneView::OnWaveInData(WPARAM wParam, LPARAM lParam)
  346.     UINT retval;
  347.     LPWAVEHDR lpWaveHdr;      
  348.                      
  349.    // Each time this is called by the system, we have a newly digitized buffer in the
  350.    // WAVE_FORMAT_PCM format, ready for compression and transmission.
  351.    //                                       
  352.    // We prep the buffer for deallocation, put it into an MFC object list for 
  353.    // processing by the compression thread.  If the recording process is still
  354.    // in progress, we supply the WaveIn device with more buffers to avoid choking
  355.    // it.
  356.    
  357.    lpWaveHdr = (LPWAVEHDR) lParam;   
  358.    
  359.   // unprepare immediately
  360.   waveInUnprepareHeader(m_hWaveIn, lpWaveHdr, sizeof(WAVEHDR));
  361.       
  362.   // Store Processed Buffers in our List Here
  363.   m_bufList.Add((DWORD) lParam); 
  364.   TRACE("Got another buffer of %ld bytes, and %s.\n", lpWaveHdr->dwBytesRecorded,
  365.          (lpWaveHdr->dwBufferLength == lpWaveHdr->dwBytesRecorded) ? "sending another":
  366.          "stopping");
  367.          
  368.   // Refill the Driver with at least another buffer!
  369.   // Only if it is not the end of recording. DO NOT send anymore buffer!                    
  370.   // NOTE: a very weak check for recording-in-progress, should be made stronger
  371.   if (lpWaveHdr->dwBytesRecorded == lpWaveHdr->dwBufferLength) // full buffer
  372.   { 
  373.    // note the value of lpWaveHdr will be changed by the next call
  374.     if(MakeWaveInBuffer(m_hWaveIn, lpWaveHdr, PHONE_WAVEIN_BUFSIZE)== FALSE)
  375.     {                   
  376.     return 0L;             
  377.     }
  378.     if (retval = waveInAddBuffer(m_hWaveIn, lpWaveHdr,  sizeof(WAVEHDR)))
  379.     {
  380.     AfxGetMainWnd()->MessageBox("Recycling: Cannot add buffer to driver pool!");
  381.     DestroyWaveInBuffer(m_hWaveIn, lpWaveHdr);
  382.     m_recording = FALSE;
  383.     return 0L;
  384.     }       
  385.    }                                             
  386.    
  387.    // tell background thread to start compressing if not already set
  388.    if (m_compressWork == FALSE) 
  389.    {
  390.      m_compressWork = TRUE;
  391.      m_state.doneBuffer = FALSE;
  392.    }
  393.    
  394. return 0L;
  395. }
  396.  
  397. LRESULT CPhoneView::OnWaveInOpen(WPARAM wParam, LPARAM lParam)
  398. {   
  399. // Not used currently          
  400. //MessageBox("Hi, I'm Here!");
  401. return 0L;
  402. }                            
  403.  
  404. LRESULT CPhoneView::OnWaveOutDone(WPARAM wParam, LPARAM lParam)
  405. {   
  406.   LPWAVEHDR lpWaveHdr;   
  407.   LPWAVEINST lpWaveInst;
  408.   BOOL LastBlock;
  409.  
  410.    // Each time this is called by the system, we have another audio buffer
  411.    // finished playing.  It is time to de-allocate the resources used by
  412.    // the audio buffer at this point.
  413.    //
  414.    // For the last audio block, we shut off the WaveOut device and reset
  415.    // playback statistics.
  416.    
  417.   // clean up the returned block
  418.   lpWaveHdr = (LPWAVEHDR) lParam;  
  419.   
  420.   // close up everything if it is the last block
  421.   lpWaveInst = (LPWAVEINST) lpWaveHdr->dwUser;
  422.   LastBlock = lpWaveInst->LastBlock;  
  423.   
  424.   DestroyWaveOutBuffer(m_hWaveOut, lpWaveHdr); // clean the block
  425.   
  426.   if ( LastBlock == TRUE)
  427.    {
  428.    waveOutClose(m_hWaveOut);
  429.    m_hWaveOut = 0;   
  430.     // set up compression buffer
  431.     m_CompBufSize = 0L;   
  432.    }
  433.    
  434.  
  435.   return 0L;
  436. }
  437.  
  438. LRESULT CPhoneView::OnRecordDone(WPARAM wParam, LPARAM lParam)
  439. {    
  440.   // Message indicating that recording has completed.  We simply
  441.   // turn off the WaveIn device at this point. Note that we cannot
  442.   // turn off the device any earlier because there may have been some
  443.   // more buffers to clear.  Remember that we're simulating a multi-threaded
  444.   // behaviour with segmented sequentially executed code!
  445.     
  446.     waveInClose(m_hWaveIn);
  447.     m_hWaveIn = 0;    // free up the device for playing
  448.        
  449.            
  450.     TRACE("Closed input device.\n");
  451.                               
  452.   // We cannot do anymore here.  If we open output device or start decompression,
  453.   // lockup WILL occur.  Instead, we delegate the responsibility to the background
  454.   // threads processing in the idle loop.
  455.                                 
  456.  return 0L;
  457. }  
  458. ////////////////////////////////////////////////////////////////////
  459. // Audio Buffer Management Routines                                 
  460. //
  461. // These are the 'standard' low level audio buffers allocation,
  462. // priming, de-priming, and de-allocation routines.  Extremely tedious 
  463. // and non-interesting, note also that error handling is very poor 
  464. // currently:  we just pop up application model dialog boxes.
  465. //
  466. BOOL CPhoneView::MakeWaveInBuffer(HWAVEIN hWaveIn, LPWAVEHDR &lpWaveHdr, DWORD dwBufSize)  // Create a New buffer
  467. {   
  468.     HGLOBAL  hData, hWaveHdr, hWaveInst;
  469.     HPSTR lpData;
  470.     LPWAVEINST lpWaveInst;
  471.  
  472.     // get the first buffer             
  473.     hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, dwBufSize);
  474.     if (!hData)
  475.     {
  476.       AfxGetMainWnd()->MessageBox("cannot allocate buffer!");
  477.       return FALSE;
  478.     }             
  479.     if ((lpData = (HPSTR) GlobalLock(hData))== NULL)  
  480.      {
  481.        AfxGetMainWnd()->MessageBox("cannot lock memory for buffer!");
  482.        GlobalFree(hData);
  483.        return FALSE;
  484.      }                
  485.     
  486.         
  487.     /* Allocate a waveform data header. The WAVEHDR must be 
  488.      * globally allocated and locked.
  489.      */
  490.     hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
  491.                            (DWORD) sizeof(WAVEHDR));
  492.     if (!hWaveHdr)
  493.     {
  494.         GlobalUnlock( hData );
  495.         GlobalFree( hData );
  496.         MessageBox( "Not enough memory for header.",
  497.                    NULL, MB_OK | MB_ICONEXCLAMATION);
  498.         return FALSE;
  499.     }
  500.     lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);
  501.     if (!lpWaveHdr)
  502.     {
  503.         GlobalUnlock( hData );
  504.         GlobalFree( hData );
  505.         GlobalFree( hWaveHdr );
  506.         AfxGetMainWnd()->MessageBox( "Failed to lock memory for header.",
  507.                    NULL, MB_OK | MB_ICONEXCLAMATION);
  508.         return FALSE;
  509.     }
  510.  
  511.     /* Allocate and set up instance data for waveform data block.
  512.      * This information is needed by the routine that frees the
  513.      * data block after it has been played.
  514.      */
  515.     hWaveInst = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
  516.                             (DWORD) sizeof(WAVEINST));
  517.     if (!hWaveInst)
  518.     {
  519.         GlobalUnlock( hData );
  520.         GlobalFree( hData );
  521.         GlobalUnlock( hWaveHdr );
  522.         GlobalFree( hWaveHdr );
  523.         AfxGetMainWnd()->MessageBox( "Not enough memory for instance data.",
  524.                    NULL, MB_OK | MB_ICONEXCLAMATION);
  525.         return FALSE;
  526.     }
  527.     lpWaveInst = (LPWAVEINST) GlobalLock(hWaveInst);
  528.     if (!lpWaveInst)
  529.     {
  530.         GlobalUnlock( hData );
  531.         GlobalFree( hData );
  532.         GlobalUnlock( hWaveHdr );
  533.         GlobalFree( hWaveHdr );
  534.         GlobalFree( hWaveInst );
  535.         AfxGetMainWnd()->MessageBox("Failed to lock memory for instance data.",
  536.                    NULL, MB_OK | MB_ICONEXCLAMATION);
  537.         return FALSE;
  538.     }
  539.     lpWaveInst->hWaveInst = hWaveInst;
  540.     lpWaveInst->hWaveHdr = hWaveHdr;
  541.     lpWaveInst->hWaveData = hData;
  542.         
  543.     /* Set up WAVEHDR structure and prepare it to be written to wave device.
  544.      */
  545.     lpWaveHdr->lpData = lpData;
  546.     lpWaveHdr->dwBufferLength = dwBufSize;
  547.     lpWaveHdr->dwBytesRecorded = 0L;    
  548.     lpWaveHdr->dwFlags = 0L;
  549.     lpWaveHdr->dwLoops = 0L;
  550.     lpWaveHdr->dwUser = (DWORD) lpWaveInst;
  551.     if(waveInPrepareHeader(hWaveIn, lpWaveHdr, sizeof(WAVEHDR)))
  552.     {
  553.         GlobalUnlock( hData );
  554.         GlobalFree( hData );
  555.         GlobalUnlock( hWaveHdr );
  556.         GlobalFree( hWaveHdr );
  557.         GlobalUnlock( hWaveInst );
  558.         GlobalFree( hWaveInst );
  559.         AfxGetMainWnd()->MessageBox( "Unable to prepare wave header.",
  560.                    NULL, MB_OK | MB_ICONEXCLAMATION);
  561.         return FALSE;           
  562.      }               
  563.  return TRUE;    
  564. }
  565. BOOL CPhoneView::MakeWaveOutBuffer(HWAVEIN hWaveIn, HWAVEOUT hWaveOut, LPWAVEHDR &lpWaveHdr, DWORD dwBufSize)
  566.     /* Set up WAVEHDR structure and prepare it to be written to wave device.
  567.      
  568.     lpWaveHdr->dwBufferLength = lpWaveHdr->dwBytesRecorded;
  569.     lpWaveHdr->dwBytesRecorded = 0L;    
  570.     lpWaveHdr->dwFlags = 0L;
  571.     lpWaveHdr->dwLoops = 0L;
  572.  
  573.   // no need for hWaveIn since the header is unprepared before storage
  574.   if (waveOutPrepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR)))
  575.   {
  576.   AfxGetMainWnd()->MessageBox("Cannot transform inbuf to outbuf?");
  577.   return FALSE;
  578.   } 
  579.   return TRUE;   
  580.   */
  581.   
  582.     HGLOBAL  hData, hWaveHdr, hWaveInst;
  583.     HPSTR lpData;
  584.     LPWAVEINST lpWaveInst;
  585.  
  586.     // get the first buffer             
  587.     hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, dwBufSize);
  588.     if (!hData)
  589.     {
  590.       AfxGetMainWnd()->MessageBox("cannot allocate buffer!");
  591.       return FALSE;
  592.     }             
  593.     if ((lpData = (HPSTR) GlobalLock(hData))== NULL)  
  594.      {
  595.        AfxGetMainWnd()->MessageBox("cannot lock memory for buffer!");
  596.        GlobalFree(hData);
  597.        return FALSE;
  598.      }                
  599.     
  600.         
  601.     /* Allocate a waveform data header. The WAVEHDR must be 
  602.      * globally allocated and locked.
  603.      */
  604.     hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
  605.                            (DWORD) sizeof(WAVEHDR));
  606.     if (!hWaveHdr)
  607.     {
  608.         GlobalUnlock( hData );
  609.         GlobalFree( hData );
  610.         MessageBox( "Not enough memory for header.",
  611.                    NULL, MB_OK | MB_ICONEXCLAMATION);
  612.         return FALSE;
  613.     }
  614.     lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);
  615.     if (!lpWaveHdr)
  616.     {
  617.         GlobalUnlock( hData );
  618.         GlobalFree( hData );
  619.         GlobalFree( hWaveHdr );
  620.         AfxGetMainWnd()->MessageBox( "Failed to lock memory for header.",
  621.                    NULL, MB_OK | MB_ICONEXCLAMATION);
  622.         return FALSE;
  623.     }
  624.  
  625.     /* Allocate and set up instance data for waveform data block.
  626.      * This information is needed by the routine that frees the
  627.      * data block after it has been played.
  628.      */
  629.     hWaveInst = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
  630.                             (DWORD) sizeof(WAVEINST));
  631.     if (!hWaveInst)
  632.     {
  633.         GlobalUnlock( hData );
  634.         GlobalFree( hData );
  635.         GlobalUnlock( hWaveHdr );
  636.         GlobalFree( hWaveHdr );
  637.         AfxGetMainWnd()->MessageBox( "Not enough memory for instance data.",
  638.                    NULL, MB_OK | MB_ICONEXCLAMATION);
  639.         return FALSE;
  640.     }
  641.     lpWaveInst = (LPWAVEINST) GlobalLock(hWaveInst);
  642.     if (!lpWaveInst)
  643.     {
  644.         GlobalUnlock( hData );
  645.         GlobalFree( hData );
  646.         GlobalUnlock( hWaveHdr );
  647.         GlobalFree( hWaveHdr );
  648.         GlobalFree( hWaveInst );
  649.         AfxGetMainWnd()->MessageBox("Failed to lock memory for instance data.",
  650.                    NULL, MB_OK | MB_ICONEXCLAMATION);
  651.         return FALSE;
  652.     }
  653.     lpWaveInst->hWaveInst = hWaveInst;
  654.     lpWaveInst->hWaveHdr = hWaveHdr;
  655.     lpWaveInst->hWaveData = hData;
  656.     lpWaveInst->LastBlock = FALSE;  // most are not last block
  657.         
  658.     /* Set up WAVEHDR structure and prepare it to be written to wave device.
  659.      */
  660.     lpWaveHdr->lpData = lpData;
  661.     lpWaveHdr->dwBufferLength = dwBufSize;
  662.     lpWaveHdr->dwBytesRecorded = 0L;    
  663.     lpWaveHdr->dwFlags = 0L;
  664.     lpWaveHdr->dwLoops = 0L;
  665.     lpWaveHdr->dwUser = (DWORD) lpWaveInst;
  666.     if(waveOutPrepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR)))
  667.     {
  668.         GlobalUnlock( hData );
  669.         GlobalFree( hData );
  670.         GlobalUnlock( hWaveHdr );
  671.         GlobalFree( hWaveHdr );
  672.         GlobalUnlock( hWaveInst );
  673.         GlobalFree( hWaveInst );
  674.         AfxGetMainWnd()->MessageBox( "Unable to prepare wave out header.",
  675.                    NULL, MB_OK | MB_ICONEXCLAMATION);
  676.         return FALSE;           
  677.      }               
  678.  return TRUE;    
  679.  
  680. }
  681.  
  682. BOOL CPhoneView::DestroyWaveInBuffer(HWAVEIN hWaveIn, LPWAVEHDR lpWaveHdr)
  683. {  
  684.    LPWAVEINST lpWaveInst;
  685.    if (hWaveIn)  // don't bother if not necessary
  686.      waveInUnprepareHeader(hWaveIn, lpWaveHdr, sizeof(WAVEHDR) );
  687.    lpWaveInst = (LPWAVEINST) lpWaveHdr->dwUser;   
  688.    GlobalUnlock( lpWaveInst->hWaveData );
  689.    GlobalFree( lpWaveInst->hWaveData );
  690.    GlobalUnlock( lpWaveInst->hWaveHdr );
  691.    GlobalFree( lpWaveInst->hWaveHdr );
  692.    GlobalUnlock( lpWaveInst->hWaveInst );
  693.    GlobalFree( lpWaveInst->hWaveInst );   
  694.    return (TRUE);
  695.  
  696. }
  697.  
  698. BOOL CPhoneView::DestroyWaveOutBuffer(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveHdr)
  699. {  
  700.    LPWAVEINST lpWaveInst;
  701.    
  702.    waveOutUnprepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR) );
  703.    lpWaveInst = (LPWAVEINST) lpWaveHdr->dwUser;   
  704.    GlobalUnlock( lpWaveInst->hWaveData );
  705.    GlobalFree( lpWaveInst->hWaveData );
  706.    GlobalUnlock( lpWaveInst->hWaveHdr );
  707.    GlobalFree( lpWaveInst->hWaveHdr );
  708.    GlobalUnlock( lpWaveInst->hWaveInst );
  709.    GlobalFree( lpWaveInst->hWaveInst );   
  710.    return (TRUE);
  711.  
  712. }
  713.  
  714. ///////////////////////////////////////////////////////////////////////
  715. // Compression and Expansion routines    
  716. //
  717. // These are helper routines for the GSM compression and decompression.
  718. //
  719. LRESULT CPhoneView::CompressABuffer(HPSTR lpData, DWORD lsize)
  720. {         
  721.  ULONG maxIter;   
  722.  //
  723.  // Compress the buffer pointed to by lpData of size lsize
  724.  // and store data into the internal m_CompressedBuf[]
  725.  //
  726.  maxIter = lsize / GSM_FRAME_SIZE;  // do up to last GSM_FRAME_SIZE block
  727. #ifdef HIGH_FIDELITY
  728.  maxIter /= 2;            // 16 bit handling
  729. #endif 
  730.  ULONG linearCount = 0L;
  731.  for (ULONG i=0; i<maxIter; i++)
  732.  {
  733.   for (UINT j=0; j<GSM_FRAME_SIZE; j++)
  734.   { 
  735.   short c;  
  736. #ifdef HIGH_FIDELITY
  737.    c =  *((short far *)(lpData +linearCount));  
  738. //  16 bit samples are SIGNED!!  so we don't need:   c ^= 0x8000;  
  739.    m_sample[j] = c;
  740.    linearCount += 2;
  741. #else  
  742.   c = ((short) (lpData[linearCount++] ^ 128));
  743.   m_sample[j] = (c << 8) + 8; 
  744. #endif  
  745.   }                                    
  746.   gsm_encode(m_hGsm, m_sample, m_GsmBuf); 
  747.   AddOut((LPSTR) m_GsmBuf, sizeof(m_GsmBuf)); 
  748.  } 
  749.  
  750.  return 0L;
  751. }
  752.  
  753. LRESULT CPhoneView::CompressPartialBuffer(LPTSTATE state)
  754. {
  755.   // Yuk!  This is part of a 'flattened' multi-loop used by the background thread
  756.   // (in the idle loop) to perform a 'partial buffer compression'
  757.   // each time an idle time slice is available.  All done in the name
  758.   // of a 'better behaved' Windows application.  It will perform one
  759.   // GSM frame worth of compression and then return control back to
  760.   // the message pump as long as work is still available.
  761.   //
  762.   if (state->maxIter == 0)
  763.   {
  764.    state->maxIter = state->lpWaveHdr->dwBytesRecorded / GSM_FRAME_SIZE;
  765. #ifdef HIGH_FIDELITY
  766.  state->maxIter /= 2;            // 16 bit handling
  767. #endif  
  768.    state->linearCount = 0L;
  769.    state->i = 0L;          
  770.    state->doneBuffer = FALSE;  
  771. TRACE("Did One Buffer with comp buf size at %lu.\n", m_CompBufSize);   
  772.   }
  773.   
  774.   if (state->i < state->maxIter)
  775.   {    
  776.   // do a GSM FRAME
  777.   HPSTR lpData;  
  778.   lpData = (HPSTR) state->lpWaveHdr->lpData;
  779.   for (UINT j=0; j<GSM_FRAME_SIZE; j++)
  780.   { 
  781.   short c;  
  782. #ifdef HIGH_FIDELITY
  783.    c =  *((short far *)(lpData + state->linearCount));  
  784. //  16 bit samples are SIGNED!!  so we don't need:   c ^= 0x8000;  
  785.    m_sample[j] = c;
  786.    state->linearCount += 2;
  787. #else  
  788.   c = ((short) (lpData[state->linearCount++] ^ 128));
  789.  
  790.  // lpData[linearCount] ^= 128;  // switch unsigned to signed
  791.  // m_sample[j] = U2S(lpData[linearCount]);         
  792.   m_sample[j] = (c << 8) + 8; 
  793. #endif  
  794.   }   // of for                                 
  795.   gsm_encode(m_hGsm, m_sample, m_GsmBuf); 
  796.   AddOut((LPSTR) m_GsmBuf, sizeof(m_GsmBuf)); 
  797.   
  798.   
  799.   state->i += 1;
  800.   return 0L;
  801.   }     // of if state->i < state->maxIter
  802.  else
  803.   {                         
  804.    state->maxIter = 0;
  805.    state->doneBuffer = TRUE;   
  806.    DestroyWaveInBuffer(m_hWaveIn, state->lpWaveHdr);
  807.  
  808.    return 1L; // completed
  809.   }
  810. }
  811.  
  812. void CPhoneView::AddOut(LPSTR sbuf, UINT lsize)
  813.   // Data Mover Helper, make the main code somewhat less messy
  814.   //
  815.   // add an GSM frame or buffer to the CompressedBuf
  816.   for (UINT j=0; j<lsize; j++)
  817.   {
  818.     m_CompressedBuf[m_CompBufSize++] = sbuf[j];
  819.   }
  820. }                       
  821.  
  822. LRESULT CPhoneView::ExpandWaveOut(HGLOBAL hMem, HPSTR CompressedBuf, ULONG CompBufSize)
  823. {
  824.  UINT retval;        
  825.  PCMWAVEFORMAT format;
  826.  
  827.   // The Listener has spawned a server and the server has received all the compressed
  828.   // audiodata.  We now prime and open the WaveOut device for playback, prep an audio
  829.   // buffer, and start the background de-compression thread on its merry way.
  830.   //       
  831. // Open Audio Output Device
  832. #ifdef HIGH_FI_OUT       
  833.     format.wf.wFormatTag =  WAVE_FORMAT_PCM;
  834.     format.wf.nChannels = 1;
  835.     format.wf.nSamplesPerSec = 11025;
  836.     format.wf.nAvgBytesPerSec = 22050;
  837.     format.wf.nBlockAlign = 2;
  838.     format.wBitsPerSample = 16; 
  839. #else 
  840.     format.wf.wFormatTag =  WAVE_FORMAT_PCM;
  841.     format.wf.nChannels = 1;
  842.     format.wf.nSamplesPerSec = 11025;
  843.     format.wf.nAvgBytesPerSec = 11025;
  844.     format.wf.nBlockAlign = 1;
  845.     format.wBitsPerSample = 8; 
  846. #endif /*   don't implement yet... */
  847.     
  848.     // Try and open audio output device.  If failure, should try again later
  849.     // just in case it is currently recording.    
  850.     if(retval = waveOutOpen( (LPHWAVEOUT) &m_hWaveOut, 0, (LPWAVEFORMAT) &format,  
  851.     (UINT) m_hWnd,(DWORD) 0,(DWORD) CALLBACK_WINDOW))
  852.     { 
  853.     AfxGetMainWnd()->MessageBox("Cannot open audio output device!");     
  854.     m_transmitting = FALSE;
  855.     return 0L;
  856.     } 
  857.     // else
  858.     // {
  859.     //   SHOULD HANDLE DELAYED-RETRY HERE ON A TIMER IN THE FUTURE
  860.     // }
  861.             
  862.  TRACE("Begin expansion...\n");
  863.  if(MakeWaveOutBuffer(m_hWaveIn, m_hWaveOut, m_dstate.lpWaveHdr, (DWORD)PHONE_WAVEOUT_BUFSIZE)== FALSE)  
  864.   {
  865.   AfxGetMainWnd()->MessageBox("Cannot allocate waveout buffers.");
  866.   return 0L;
  867.   }                     
  868.   
  869.  // set up background thread states and let idle-processing handle it       
  870.  m_dstate.lpData = m_dstate.lpWaveHdr->lpData;
  871.  
  872.  m_dstate.linear = 0;  // counter for Play Buffer fill   
  873.  m_dstate.b = 0;       // counter for GSM FRAME fill
  874.  m_dstate.CompressedBuf = CompressedBuf;
  875.  m_dstate.CompBufSize = CompBufSize;
  876.  
  877.  m_dstate.i = 0;
  878.  m_decompressWork = TRUE;
  879.                                 
  880.  m_hspeechBuffer = hMem; // used for memory deallocation later
  881.  
  882.     return 0L;
  883. }  
  884.  
  885. LRESULT CPhoneView::PlayWaveInBuffer(LPWAVEHDR lpWaveHdr)
  886. {                                                   
  887.  LPWAVEINST lpWaveInst;
  888.  lpWaveInst = (LPWAVEINST) lpWaveHdr->dwUser;
  889.  lpWaveInst->LastBlock = FALSE;
  890.  UINT retval;                   
  891.  //
  892.  // routine used in testing only
  893.     lpWaveHdr->dwBufferLength = lpWaveHdr->dwBytesRecorded;
  894.     lpWaveHdr->dwBytesRecorded = 0L;    
  895.     lpWaveHdr->dwFlags = 0L;
  896.     lpWaveHdr->dwLoops = 0L;
  897.  
  898.     if(waveOutPrepareHeader(m_hWaveOut, lpWaveHdr, sizeof(WAVEHDR)))
  899.     {
  900.          DestroyWaveOutBuffer(m_hWaveOut, lpWaveHdr);
  901.         AfxGetMainWnd()->MessageBox( "Unable to prepare wave out header.",
  902.                    NULL, MB_OK | MB_ICONEXCLAMATION);
  903.         return 1L;           
  904.      }               
  905.         if (retval = waveOutWrite(m_hWaveOut, lpWaveHdr, sizeof(WAVEHDR)))
  906.          {
  907.           AfxGetMainWnd()->MessageBox("Cannot write buffer to output device!");
  908.           DestroyWaveOutBuffer(m_hWaveOut, lpWaveHdr);
  909.           m_transmitting = FALSE;
  910.           return 1L;                                        
  911.           }                    
  912.                                                   
  913.   return 0L;                                                  
  914.                                                   
  915. }  
  916.  
  917. BOOL CPhoneView::DoIdleProcessing(void)
  918. {     
  919.    UINT retval;          
  920.    //  
  921.    // This function is called everything the system is Idle.  We use this
  922.    // chance to perform our background compression and de-compression.
  923.    //
  924.    // Both of these 'background threads' are multi-nested-loops which are
  925.    // 'flattened' in order to perform a very small unit of work on every
  926.    // idle opportunity.  This keeps the application well behaving under
  927.    // Windows.
  928.    //
  929.    UINT numBuf = m_bufList.GetSize();   
  930.  
  931.  if (m_ListenerStarted == FALSE)
  932.  {    
  933.     // start up listener if not started
  934.     m_TalkListener.StartListener(NULL, IGP_PORT, (LPWSADDRESS) &m_ListenerAddress, m_hWnd, NULL, this);
  935.     m_ListenerStarted = TRUE; 
  936.     m_ClientAddress = m_TalkListener.MyAddress();
  937.     GetEditCtrl().SetSel(-1,-1);
  938.     GetEditCtrl().ReplaceSel((LPSTR) "IGP Listener started\r\n");
  939.  }
  940.                                         
  941.  // THE COMPRESSION THREAD                                        
  942.  // We have very little time, really
  943.  // do just 1 GSM frame
  944.  if (m_compressWork == TRUE)
  945.  { 
  946.  
  947.  
  948.     if (m_state.doneBuffer == TRUE)
  949.    { 
  950.    
  951.      m_state.doneBuffer = FALSE;
  952.  
  953.      // can't check for 1 left, since recording  maybe in progress
  954.      if (( m_recording == FALSE) && (numBuf <=1))
  955.      {                     
  956.         LPWAVEHDR lpWaveHdr = (LPWAVEHDR) m_bufList[0];
  957.         DestroyWaveInBuffer(m_hWaveIn,lpWaveHdr);
  958.         m_bufList.RemoveAll();
  959. TRACE("Pull last buffer.\n");
  960.          m_transmitting = TRUE;             
  961.          m_compressWork = FALSE;   
  962.          
  963.          // reset here, otherwise face major re-entrancy problems
  964.          m_state.doneBuffer = FALSE;  // nothing to do initially 
  965.         m_state.maxIter = 0L;
  966.         m_state.linearCount = 0; 
  967.         m_state.i = 0L; 
  968.         m_state.lpWaveHdr = (LPWAVEHDR) 0;
  969.         m_state.lpData = (HPSTR) 0;         
  970.  
  971.         // signifies completion of background compress thread         
  972.          PostMessage(PHONEMSG_COMPRESS_DONE);  
  973.          return 0;
  974.      }
  975.      else
  976.      {
  977.          if (numBuf >= 1)
  978.          {                  
  979. TRACE("Pull a buffer because DoneFlag!\n");         
  980.          // load up new buffer
  981.          m_state.lpWaveHdr = (LPWAVEHDR) m_bufList[0];   
  982.          m_state.lpData = (HPSTR) m_state.lpWaveHdr->lpData;
  983.          m_bufList.RemoveAt(0);
  984.          }
  985.       } // of else    
  986.     } // of Done Buffer == TRUE 
  987.     else // first time only
  988.     {
  989.       if ((numBuf >=1) && (m_state.lpWaveHdr == (LPWAVEHDR) 0))
  990.       { 
  991. TRACE("First time only pull buffer!\n");       
  992.         // load up new buffer
  993.          m_state.lpWaveHdr = (LPWAVEHDR) m_bufList[0];   
  994.          m_state.lpData = (HPSTR) m_state.lpWaveHdr->lpData;
  995.          m_bufList.RemoveAt(0);
  996.  
  997.       }
  998.     }                           
  999.     if (((m_recording == TRUE) && (numBuf >= 1))
  1000.     || ((m_recording == FALSE)/* && (numBuf <=1)*/))  // during recording, numbuf may = 0
  1001.       CompressPartialBuffer((LPTSTATE) &m_state);    
  1002.     return 1;    
  1003.   } // of m_compressWork
  1004.  
  1005.  // THE DECOMPRESSION THREAD                                        
  1006.  // We have very little time, do just 1 GSM frame.
  1007.  // Everytime we finish decompression a complete audio buffer,
  1008.  // we'll send it to WaveOut for playback from here.
  1009.  
  1010.  if (m_decompressWork == TRUE)
  1011.    {
  1012.       //for( UINT i=0; i<CompBufSize; i++)
  1013.       //if (m_dstate.i < m_dstate.CompBufSize)
  1014.       for (UINT i=0; (i<sizeof(m_GsmBuf)) && (m_dstate.i < m_dstate.CompBufSize);
  1015.           i++)
  1016.       {
  1017.         m_GsmBuf[i] = m_dstate.CompressedBuf[m_dstate.i];
  1018.         m_dstate.i++;
  1019.       }   
  1020.       
  1021.           gsm_decode(m_hGsm, m_GsmBuf, m_sample);  // no error check here for simplicity
  1022.               
  1023.           for (UINT aa =0; aa <  GSM_FRAME_SIZE; aa++)   {
  1024. #ifdef HIGH_FI_OUT                                     
  1025.            // 16 bit samples are signed automagically
  1026.            *((short far *) (m_dstate.lpData + m_dstate.linear)) = m_sample[aa];
  1027.            m_dstate.linear += 2;
  1028. #else   
  1029.           // 8 bit samples need are unsigned and need changes
  1030.           char c = (char) ((m_sample[aa]) >> 8) ;     
  1031. //        unsigned char c = S2U(m_sample[aa]); 
  1032.           c ^= 128;  // put it back to unsigned
  1033.           m_dstate.lpData[m_dstate.linear++] = c;
  1034. #endif        
  1035.            }  // of for aa     
  1036.            
  1037.        if (m_dstate.i < m_dstate.CompBufSize)
  1038.         {    
  1039.  
  1040.          if (m_dstate.linear == PHONE_WAVEOUT_BUFSIZE)  
  1041.          {                        
  1042.            if (m_dstate.i == m_dstate.CompBufSize - 1) // special case of alignment
  1043.            {
  1044.             // mark last block
  1045.             m_dstate.lpWaveInst = (LPWAVEINST) m_dstate.lpWaveHdr->dwUser;
  1046.             m_dstate.lpWaveInst->LastBlock = TRUE;                              
  1047.            }
  1048.            m_dstate.linear = 0L; 
  1049.            
  1050.            TRACE("Printing 32 output buffer values:\n");
  1051.            /* for (UINT j=0; j<32; j++) 
  1052.             {
  1053.              TRACE ("C:%x ", (unsigned)lpData[j]); }
  1054.              TRACE("\n");
  1055.             */
  1056.            // send the data to play   
  1057.            if (retval = waveOutWrite(m_hWaveOut, m_dstate.lpWaveHdr, sizeof(WAVEHDR)))
  1058.            {
  1059.              AfxGetMainWnd()->MessageBox("Cannot write buffer to output device!");
  1060.              DestroyWaveOutBuffer(m_hWaveOut, m_dstate.lpWaveHdr);
  1061.              return 0L;                                        
  1062.            }                    
  1063.            TRACE("Decompressed and sent a buffer of size %ld to output.\n",
  1064.                m_dstate.lpWaveHdr->dwBufferLength); 
  1065.           // sent one, make another buffer ready                                                      
  1066.            if(MakeWaveOutBuffer(m_hWaveIn, m_hWaveOut, m_dstate.lpWaveHdr, 
  1067.             (DWORD)PHONE_WAVEOUT_BUFSIZE)== FALSE)  
  1068.               {
  1069.                   AfxGetMainWnd()->MessageBox("Cannot allocate waveout buffers.");
  1070.                   return 0L;
  1071.               }           
  1072.            m_dstate.lpData = m_dstate.lpWaveHdr->lpData;  // vital -> forgot this in a bug?
  1073.          }  // of linear == PHONEWAVEOUT SIZE  
  1074.  
  1075.       return 1;
  1076.      } // of (if  i < compbufSize)
  1077.      else
  1078.      {  // i >= compbufSize
  1079.        if (m_dstate.linear != 0L)
  1080.         {
  1081.           // handle final block
  1082.           m_dstate.lpWaveInst = (LPWAVEINST) m_dstate.lpWaveHdr->dwUser;
  1083.           m_dstate.lpWaveInst->LastBlock = TRUE;                              
  1084.           m_dstate.lpWaveHdr->dwBufferLength = m_dstate.linear;
  1085.           if (retval = waveOutWrite(m_hWaveOut, m_dstate.lpWaveHdr, sizeof(WAVEHDR)))
  1086.           {
  1087.              AfxGetMainWnd()->MessageBox("Cannot write buffer to output device!");
  1088.              DestroyWaveOutBuffer(m_hWaveOut, m_dstate.lpWaveHdr);
  1089.              m_decompressWork = FALSE;
  1090.              m_transmitting = FALSE;
  1091.              return 0L ;                                        
  1092.            }                        
  1093.           m_decompressWork = FALSE;
  1094.           
  1095.           // free the speech buffer now
  1096.            if (m_hspeechBuffer)
  1097.                {
  1098.                    GlobalUnlock(m_hspeechBuffer);
  1099.                    GlobalFree(m_hspeechBuffer);
  1100.                }                                 
  1101.           TRACE("Printing 32 output buffer values:\n");
  1102.           for (UINT j=0; j<32; j++) 
  1103.            {
  1104.             TRACE ("C:%x ", (unsigned)m_dstate.lpData[j]); 
  1105.            }
  1106.             TRACE("\n");
  1107.  
  1108.              TRACE("Decompressed and sent LAST buffer of size %ld to output.\n",
  1109.                m_dstate.lpWaveHdr->dwBufferLength); 
  1110.                 
  1111.          } // of linear !=0  
  1112.       } // of else  i>=bufsize
  1113.   } // of decompressWork == TRUE      
  1114.   
  1115. return 0;
  1116. }
  1117.  
  1118. ////////////////////////////////////////////////////////////////////////
  1119. // Misc routines
  1120. //
  1121.  
  1122. void CPhoneView::OnFileOpen()
  1123. {
  1124.     // Pop a dialog box and allow user to enter the IP address to talk to here 
  1125.     CDlgHostID abc;                       
  1126.  
  1127.        abc.m_InetAddress = (ULONG) m_ClientAddress;
  1128.  
  1129.     if (abc.DoModal() == IDOK)    
  1130.       m_ClientAddress = (WSADDRESS) WSNToHL(abc.m_InetAddress);
  1131.     
  1132. }                            
  1133.  
  1134. LRESULT CPhoneView::OnClientNotify(WPARAM wParam, LPARAM lParam)
  1135. {                  
  1136.  // clearing house function for status, error messages and connection troubles 
  1137.  //
  1138.  UINT event, errcode;
  1139.  char tps[90];   // Pardon that magic number!:)
  1140.  event = WSEVENT(lParam);
  1141.  errcode = WSERROR(lParam); 
  1142.  switch(event)
  1143.  {
  1144.   case WSCONNECTED: 
  1145.    if (errcode == 0)
  1146.     wsprintf(tps, "Client: Connected to Remote (%x).\r\n", errcode);
  1147.    else   
  1148.    {
  1149.     wsprintf(tps, "Client: Failed to connect to remote (%x).\r\n", errcode);
  1150.     m_recording = FALSE;
  1151.     m_transmitting = FALSE;
  1152. //    m_CompBufSize = 0;
  1153.    }
  1154.    break;   
  1155.   case WSTALKBACK:
  1156.    wsprintf(tps, "Client: Connect timer expired (%x).\r\n", errcode);
  1157.    break; 
  1158.   case WSDISCONNECTED:
  1159.    wsprintf(tps, "Client: Disconnected from remote (%x).\r\n", errcode); 
  1160.    m_hWaveIn = 0;
  1161.    m_recording=FALSE;
  1162.    m_transmitting = FALSE;
  1163.    break;   
  1164.   case WSTALKLISCONNECT:
  1165.    wsprintf(tps, "Listener: Detected remote client connection (%x).\r\n", errcode);
  1166.    break;
  1167.   case WSTALKLISFAILED:
  1168.    wsprintf(tps, "Listener: Cannot start server, low memory (%x).\r\n", errcode);
  1169.    break;  
  1170.   case WSCHILDCLOSED:
  1171.    wsprintf(tps, "Server: Remote disconnected, server freed.(%x).\r\n", errcode);
  1172.    break;  
  1173.   case WSTALKNEWCHILD:
  1174.    wsprintf(tps, "Server: A new server is started (%x).\r\n", errcode);
  1175.    break;
  1176.   case WSTALKFAILED:
  1177.    wsprintf(tps, "Client: Problem in protocol negotiation (%x).\r\n", errcode);
  1178.    break;  
  1179.   default:
  1180.     wsprintf(tps, "Client: Received event = %x,  Error = %x\r\n", event, errcode);
  1181.     break;
  1182.  }  
  1183.     GetEditCtrl().SetSel(-1,-1);
  1184.     GetEditCtrl().ReplaceSel((LPSTR) tps);
  1185.  
  1186.  
  1187.  TRACE("WINDOW RECEIVED Code Event = %x,  Error = %x\n", event, errcode); 
  1188.  
  1189. return 0L;
  1190. }            
  1191.  
  1192.